home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Qu.......ke Neue Level
/
KroGer Software GmbH - Qu_ke.iso
/
UTILITY
/
PRG8.ZIP
/
Q_MISC.C
< prev
next >
Wrap
C/C++ Source or Header
|
1996-03-02
|
10KB
|
476 lines
/*
* Copyright (C) 1996 by Raphael Quinet. All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice appear in all
* copies and that both that copyright notice and this permission
* notice appear in supporting documentation. If more than a few
* lines of this code are used in a program which displays a copyright
* notice or credit notice, the following acknowledgment must also be
* displayed on the same screen: "This product includes software
* developed by Raphael Quinet for use in the Quake Editing Utilities
* project." THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR
* IMPLIED WARRANTY.
*
* More information about the QEU project can be found on the WWW:
* "http://www.montefiore.ulg.ac.be/~quinet/games/editing.html" or by
* mail: Raphael Quinet, 9 rue des Martyrs, B-4550 Nandrin, Belgium.
*/
/*
* Q_MISC.C - Error logs, memory management, selection of objects, etc.
*
* This file was derived from D_MISC.C (Doom Editing Utilities 5.3),
* written by the DEU Team: Raphael Quinet, Brandon Wyber, Ted
* Vessenes and others.
*/
/* the includes */
#include "qeu.h"
#ifdef QEU_UNIX
#include <sys/types.h>
#include <sys/time.h>
#else
#include <dos.h>
#include <time.h>
#endif
#if defined (__TURBOC__)
#include <alloc.h>
#elif defined(__GO32__)
#include <pc.h>
#endif
#include "q_misc.h"
/*! Dirty hack while the config stuff is not available */
struct
{
Bool debug;
} Config;
/* global variable */
FILE *logfile = NULL; /* file pointer to the error log */
/*
* Wait for a specified number of milliseconds.
*/
void MSleep(int msec)
{
#ifdef QEU_UNIX
struct timeval tv;
tv.tv_sec = msec / 1000;
tv.tv_usec = 1000 * (msec % 1000);
(void) select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv);
#else
delay(msec);
#endif
}
/*
* Report a non-fatal error.
*/
void ProgWarning(char *errstr, ...)
{
va_list args;
va_start(args, errstr);
printf("\nWarning: ");
vprintf(errstr, args);
printf("\n");
if (Config.debug == TRUE && logfile != NULL)
{
fprintf(logfile, "\nWarning: *** ");
vfprintf(logfile, errstr, args);
fprintf(logfile, " ***\n");
fclose(logfile);
}
va_end(args);
}
/*
* Terminate the program reporting an error.
*/
void ProgError(char *errstr, ...)
{
va_list args;
va_start(args, errstr);
printf("\nProgram Error: *** ");
vprintf(errstr, args);
printf(" ***\n");
if (Config.debug == TRUE && logfile != NULL)
{
fprintf(logfile, "\nProgram Error: *** ");
vfprintf(logfile, errstr, args);
fprintf(logfile, " ***\n");
}
va_end(args);
exit(5);
}
/*
* Write a message in the log file.
*/
void LogMessage(char *logstr, ...)
{
va_list args;
time_t tval;
char *tstr;
if (Config.debug == TRUE && logfile != NULL)
{
va_start(args, logstr);
/* if the messsage begins with ":", output the current date & time first */
if (logstr[0] == ':')
{
time(&tval);
tstr = ctime(&tval);
tstr[strlen(tstr) - 1] = '\0';
fprintf(logfile, "%s", tstr);
}
vfprintf(logfile, logstr, args);
/* write the message immediately, in case something bad happens next */
fflush(logfile);
va_end(args);
}
}
/*
* Open the log file and write a first message in it.
*/
void OpenLogFile(char *logfilename)
{
if (Config.debug == TRUE)
{
logfile = fopen(logfilename, "a");
if (logfile == NULL)
printf("Warning: Could not open log file \"%s\"", logfilename);
LogMessage(": Starting QEU %s\n", QEU_VERSION);
}
}
/*
* Close the log file.
*/
void CloseLogFile(void)
{
if (logfile != NULL)
{
LogMessage(": The end!\n\n\n");
fclose(logfile);
}
}
/*
* Test if an object is in the selection list.
*/
Bool IsSelected(SelPtr list, Int16 objnum)
{
SelPtr cur;
for (cur = list; cur; cur = cur->next)
if (cur->objnum == objnum)
return TRUE;
return FALSE;
}
/*
* Add an object to the selection list.
*/
void SelectObject(SelPtr *list, Int16 objnum)
{
SelPtr cur;
#ifdef DEBUG
if (objnum < 0)
ProgError("BUG: SelectObject called with %d", objnum);
#endif
cur = (SelPtr) QMalloc(sizeof(struct SelectionList));
cur->next = *list;
cur->objnum = objnum;
*list = cur;
}
/*
* Remove an object from the selection list.
*/
void UnSelectObject(SelPtr *list, Int16 objnum)
{
SelPtr cur, prev;
#ifdef DEBUG
if (objnum < 0)
ProgError("BUG: UnSelectObject called with %d", objnum);
#endif
prev = NULL;
cur = *list;
while (cur)
{
if (cur->objnum == objnum)
{
if (prev)
prev->next = cur->next;
else
*list = cur->next;
QFree(cur);
if (prev)
cur = prev->next;
else
cur = NULL;
}
else
{
prev = cur;
cur = cur->next;
}
}
}
/*
* Forget the selection list.
*/
void ForgetSelection(SelPtr *list)
{
SelPtr cur, prev;
cur = *list;
while (cur)
{
prev = cur;
cur = cur->next;
QFree(prev);
}
*list = NULL;
}
/*
Note from RQ:
In order to prevent memory fragmentation on large blocks (greater
than 1K), you can define MEMORY_LOWFRAG and the size of all blocks
will be rounded up to 8K. Thus, "realloc" will move the block if
and only if it has grown or shrunk enough to cross a 8K boundary.
I don't do that for smaller blocks (smaller than 1K), because this
would waste too much space if these blocks were rounded up to 8K.
There are lots of "malloc"'s for very small strings (9 characters)
or filenames, etc.
Thanks to Craig Smith (bcs@cs.tamu.edu) for his ideas about memory
fragmentation.
*/
#ifdef MEMORY_LOWFRAG
#define SIZE_THRESHOLD 1024
#define SIZE_OF_BLOCK 4095 /* actually, this is (size - 1) */
#endif
/*
* Allocate memory with error checking.
*/
void huge *QMalloc(UInt32 size)
{
void huge *ret;
#ifdef MEMORY_LOWFRAG
/* limit fragmentation on large blocks */
if (size >= (UInt32) SIZE_THRESHOLD)
size = (size + (UInt32) SIZE_OF_BLOCK) & ~((UInt32) SIZE_OF_BLOCK);
#endif
#ifdef __TURBOC__
ret = farmalloc(size);
#else
ret = malloc(size);
#endif
if (!ret)
ProgError("out of memory (cannot allocate %lu far bytes)", size);
return ret;
}
/*
* Reallocate memory with error checking.
*/
void huge *QRealloc(void huge *old, UInt32 size)
{
void huge *ret;
#ifdef MEMORY_LOWFRAG
/* limit fragmentation on large blocks */
if (size >= (UInt32) SIZE_THRESHOLD)
size = (size + (UInt32) SIZE_OF_BLOCK) & ~((UInt32) SIZE_OF_BLOCK);
#endif
#ifdef __TURBOC__
ret = farrealloc(old, size);
#else
ret = realloc(old, size);
#endif
if (!ret)
ProgError("out of memory (cannot reallocate %lu far bytes)", size);
return ret;
}
/*
* Free memory.
*/
void QFree(void huge *ptr)
{
/* just a wrapper around farfree(), but provide an entry point */
/* for memory debugging routines... */
#ifdef __TURBOC__
farfree(ptr);
#else
free(ptr);
#endif
}
/*
* Duplicate an area of memory in a newly allocated location.
*/
UInt8 *QMemDup(UInt8 *src, UInt32 size)
{
UInt8 *ret;
UInt8 *sp, *dp;
if (src == NULL)
ProgError("BUG: cannot duplicate NULL pointer");
ret = (UInt8 *)QMalloc(size);
/* copy 32K blocks at a time, because old DOS doesn't like >64K blocks */
sp = src;
dp = ret;
while (size > 0x8000L)
{
memcpy(dp, sp, 0x8000);
sp = sp + 0x8000;
dp = dp + 0x8000;
size -= 0x8000;
}
if (size > 0)
memcpy(dp, sp, size);
return ret;
}
/*
* Duplicate a string in a newly allocated location, with error checking.
*/
char *QStrDup(char *src)
{
char *ret;
if (src == NULL)
ProgError("BUG: cannot duplicate NULL pointer");
ret = (char *)QMalloc(strlen(src) + 1);
return strcpy(ret, src);
}
/*
* Copy a string into another (like strncpy) and pad the destination string
* with zeroes. The destination string will not be null-terminated if
* strlen(src) > n.
*/
char *QStrNCpy(char *dest, char *src, int n)
{
int i;
char *dp, *sp;
dp = dest;
sp = src;
for (i = 0; *sp && i < n; i++)
*dp++ = *sp++;
for (; i < n; i++)
*dp++ = 0;
return dest;
}
/*
* Does something strange with a string... :-) Strips leading
* directory name from "src", removes the extension (anything that
* follows a dot '.'), converts the string to upper case and truncate
* it after "n" characters. Useful for making a WAD or WAD2 entry
* name from a file name.
*/
char *QStrNDupHack(char *src, int n)
{
int i;
char *ret, *dp, *sp;
if (src == NULL)
ProgError("BUG: cannot convert a NULL string to an entry name");
if (n <= 0)
ProgError("BUG: entry size must be greater than 0 (%d)", n);
sp = src;
for (dp = sp; *dp; dp++)
if (*dp == '/' || *dp == '\\')
sp = dp + 1;
ret = (char *)QMalloc(n);
dp = ret;
for (i = 0; *sp && *sp != '.' && i < n; i++)
*dp++ = (char)toupper((int)*sp++);
for (; i < n; i++)
*dp++ = 0;
return ret;
}
#ifndef QEU_DOS
/*
* Convert a string to upper case, overwriting its space.
*/
char *strupr(char *s)
{
char *cp;
if (s == NULL)
ProgError("BUG: cannot convert a NULL string to upper case");
for (cp = s; *cp != '\0'; cp++)
*cp = (char)toupper((int)*cp);
return s;
}
#endif /* QEU_DOS */
/*
* Convert numbers depending on endianness.
*/
#ifdef FAT_ENDIAN
UInt16 SwapInt16(UInt16 x)
{
return ((x<<8) & 0xff00) | ((x>>8) & 0x00ff);
}
UInt32 SwapInt32(UInt32 x)
{
return (((x << 24) & 0xff000000)
| ((x<< 8) & 0x00ff0000)
| ((x>> 8) & 0x0000ff00)
| ((x>>24) & 0x000000ff));
}
Float32 SwapFloat32(Float32 x)
{
UInt32 i;
i = SwapInt32(*((UInt32 *)&x));
return *((Float32 *)&i);
}
#endif /* FAT_ENDIAN */
/* end of file */